# -*- coding:utf-8 -*-
import tensorflow as tf
import time
from tensorflow.examples.tutorials.mnist import input_data

#加载mnist_inference.py和mnist_train.py中定义的常量和函数
import mnist_inference
import mnist_train
import numpy as np

#每10秒加载一次最新的模型，并在测试数据上测试最新模型的正确率
EVAL_INTERVAL_SECS=10
BATCH_SIZE=100
def eval(mnist):
    with tf.Graph().as_default() as g:
        #定义输入的格式
        x = tf.placeholder(
            tf.float32,
            [5000, mnist_inference.image_size, mnist_inference.image_size, mnist_inference.num_channels],
            name='x-input'
        )
        y_ = tf.placeholder(
            tf.float32,
            [None, mnist_inference.output_node],
            name='y-input'
        )
        print(x.shape)    #(?,28,28,1)
        reshaped_xs=np.reshape(mnist.validation.images,
                            (5000,
                            mnist_inference.image_size,
                            mnist_inference.image_size,
                            mnist_inference.num_channels
                                    )
                                   )
        #print(mnist.validation.images.shape)   #(5000,784)
        #print(mnist.validation.labels.shape)   #(5000,10)
        #print(reshaped_xs.shape)    #(5000, 28, 28, 1) 
        #print(type(mnist.validation.images))  #<class 'numpy.ndarray'>
        validate_feed={x:reshaped_xs,y_:mnist.validation.labels}
        #直接通过调用封装好的函数来计算前向传播的结果。
        # 因为测试时不关注正则化损失函数的值，所以这里用于计算正则化损失的函数被设为None
        y=mnist_inference.inference(x,False,None)
        #print(y.shape)

        #使用前向传播的结果计算正确率。如果需要对为止的样例进行分类，那么使用tf.argmax(y,1)就可以得到样例的预测类别了
        correct_prediction=tf.equal(tf.argmax(y,1),tf.argmax(y_,1))
        accuracy=tf.reduce_mean(tf.cast(correct_prediction,tf.float32))

        #通过变量重命名的方式来加载模型，这样在前向传播的过程中就不需要调用求滑动平均的函数来获取平均值了。
        # 这样就可以完全共用mnist_inference.py中定义的前向传播过程。
        '''
        我的理解，原本保存的模型的计算图里面会涉及到滑动平均的计算，
        如果这里不用，那么计算图无法直接使用，所以也需要滑动平均值，只是获取方式不一样了
        原本应该是用滑动平均函数来求值(滑动平均类.average(变量))，
        这里直接通过变量管理（重命名）+模型持久化（因为训练时使用了滑动平均，保存时会保存变量以及它的滑动平均值）的方式来取值，具体参考5.4.1部分内容
        '''
        variable_average=tf.train.ExponentialMovingAverage(mnist_train.MOVING_AVERAGE_DECAY)
        variable_to_restore=variable_average.variables_to_restore()
        saver=tf.train.Saver(variable_to_restore)

        #每隔EVAL_INTERVAL_SECS秒调用一次计算正确率的过程以检测训练过程中正确率的变化
        while True:
            with tf.Session() as sess:
                #tf.train.get_checkpoint_state()函数会返回checkpoint文件CheckpointState proto类型的内容，
                # 包含model_checkpoint_path和all_model_checkpoint_paths两个属性。
                # 其中model_checkpoint_path保存了最新的tensorflow模型文件的文件名，
                # all_model_checkpoint_paths则有未被删除的所有tensorflow模型文件的文件名。
                ckpt=tf.train.get_checkpoint_state(mnist_train.MODEL_SAVE_PATH)
                if ckpt and ckpt.model_checkpoint_path:       #后者是最新模型的文件名,参看5.4.2最后关于checkpoint的内容介绍
                    #加载模型
                    saver.restore(sess,ckpt.model_checkpoint_path)
                    #通过文件名得到模型保存时迭代的轮数。
                    global_step=ckpt.model_checkpoint_path.split('/')[-1].split('-')[-1]
                    accuracy_score=sess.run(accuracy,feed_dict=validate_feed)
                    print('After %s training step(s),validation accuracy=%g'%(global_step,accuracy_score))
                else:
                    print("No checkpoint file found")
                    time.sleep(EVAL_INTERVAL_SECS)

def main(argv=None):
    mnist=input_data.read_data_sets("path/mnist_data",one_hot=True)
    eval(mnist)

if __name__=='__main__':
    tf.app.run()
